package generator;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
 * @author Admin
 */
public class MyBatisGenerator {
    /**
     * TODO 根路径，建议先指向临时存放目录，生成后确认无误再手动复制到工程目录，避免失误覆盖
     */

//    private static String projectPath = "D:\\generator.MyBatisGenerator";
    /** 当前项目 */
    private static final String PROJECT_PATH = System.getProperty("user.dir");
    /** 作者 */
    private static final String AUTHOR = "dapangdong";
    /** 数据库名称 */
    private static final String DATABASE_NAME="vueblog";

    /**
     * 连接数据库的驱动类
     * mysql8之前用的是：com.mysql.jdbc.Driver。
     * mysql8之后用的是：com.mysql.cj.jdbc.Driver
    */
    private static final String DRIVERNAME="com.mysql.cj.jdbc.Driver";
    private static final String JDBC = "jdbc:mysql://localhost:3306/"+DATABASE_NAME+"?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC&allowPublicKeyRetrieval=true";

    private static final String username = "root";
    private static final String password = "123456";
    /** 项目包名 */
    private static final String Parent = "com.example.demo";
    private static final String Parents = "com/example/demo";

    /** 项目中文件的路径 */
    private static final String SRC_URL = PROJECT_PATH +"/src/main/java/";
    private static final String RESOURCES_URL = PROJECT_PATH +"/src/main/resources";

    /** 表前缀 */
    private static final String[] TABLE_PREFIX = {"m_","p_"};
    private static final String[] TABLE_NAME = {"m_user"}; //,"m_role","m_user_role"

    @Test
    public void jdbcConnect() throws ClassNotFoundException, SQLException {
        //加载驱动类
        Class.forName(DRIVERNAME);
        //用参数得到连接对象
        Connection conn= DriverManager.getConnection(JDBC,username,password);
        System.out.println("mysql连接成功！");
        System.out.println(conn);
    }

    /** 读取控制台内容 */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + "：");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "！");
    }

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator generator = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        // 生成文件的输出路径
        gc.setOutputDir(SRC_URL);
        //开发人员
        gc.setAuthor(AUTHOR);
        // 是否覆盖同名文件，默认是false
        gc.setFileOverride(true);
        // 是否打开路径
        gc.setOpen(false);
        //默认false
        // 实体属性 Swagger2 注解
        gc.setSwagger2(true);
        // XML ResultMap
        gc.setBaseResultMap(true);
        // 生成Sql片段 默认false 和basemodel相似
        gc.setBaseColumnList(true);
        /* 自定义文件命名，注意 %s 会自动填充表实体属性！ */
//        gc.setEntityName("%s");
//        gc.setControllerName("%sController");
        gc.setServiceName("%sService");
//        gc.setServiceImplName("%sServiceImpl");
//        gc.setMapperName("I%sMapper");
//        gc.setXmlName("%sMapper");
        // 指定生成的主键类型
        gc.setIdType(IdType.ID_WORKER);
        generator.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        // dsc.setSchemaName("public");
        dsc.setDbType(DbType.MYSQL);
        dsc.setDriverName(DRIVERNAME);
        dsc.setUsername(username);
        dsc.setPassword(password);
        dsc.setUrl(JDBC);
        generator.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(null);
        //代码生成到哪个包下面
        pc.setParent(Parent);
//        pc.setXml(RESOURCES_URL+"/mapper");
        //此处是所属模块名称
//         pc.setModuleName(Parent);
        generator.setPackageInfo(pc);

        // 自定义配置  (InjectionConfig方法中自定义的Map返回对象可以返回给模板调用，调用方法是${cfg.xxx})
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                //自定义参数
                Map<String, Object> map = new HashMap<>();
                map.put("datetime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                map.put("DTO", Parent+".dto");
                map.put("utils", Parent+".utils");
                this.setMap(map);
            }
        };
/**
        // 如果模板引擎是 freemarker
//        String templatePath = "/templates/mapper.xml.ftl";
        // 如果模板引擎是 velocity
         String templatePath = "/templates/mapper.xml.vm";
         String dtoPath = "/templates/entityDTO.vm";
         String htmlPath = "/templates/html.vm";

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出 mapper.xml
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
                return RESOURCES_URL + "/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });

        focList.add(new FileOutConfig(dtoPath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
                return RESOURCES_URL + "/html/" + tableInfo.getEntityName() + "List" + ".html";
            }
        });

        cfg.setFileOutConfigList(focList);
 */
        // 自定义输出配置
        cfg.setFileOutConfigList(generatorUtils.getFileOutConfig(SRC_URL+Parents, RESOURCES_URL));
        generator.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        // 配置自定义输出模板（如果不配置这些，则会按照官方的配置进行生成）
        // 指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        templateConfig.setController("templates/vm/controller.vm");
        templateConfig.setEntity("templates/vm/entity.vm");
        templateConfig.setEntityKt("templates/vm/entityDTO.vm");
        templateConfig.setService("templates/vm/service.vm");
        templateConfig.setServiceImpl("templates/vm/serviceImpl.vm");
        templateConfig.setMapper("templates/vm/mapper.vm");
        templateConfig.setXml(null);
//        templateConfig.setXml("templates/vm/mapperXml.vm");

        generator.setTemplate(templateConfig);

        // 数据库表配置
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        // 表名生成策略,驼峰命名(下划线转驼峰)
        strategy.setNaming(NamingStrategy.underline_to_camel);
        //数据库表字段映射到实体的命名策略（ 字段映射 驼峰）
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//        strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
        // 是否使用lombak 默认为false
        strategy.setEntityLombokModel(true);
        //设置controller为restcontroller ，默认false
        strategy.setRestControllerStyle(true);
        // 公共父类
//        strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
        // 默认false
        strategy.setControllerMappingHyphenStyle(true);
        //【实体】是否生成字段常量（默认 false）
//        strategy.setEntityColumnConstant(true);
        // 需要生成的表
//        strategy.setInclude(scanner("表名，多个英文逗号分割").split(","));
        strategy.setInclude(TABLE_NAME);
        // 表前缀（生成类名不会包含表前缀，多个用逗号分隔）
        strategy.setTablePrefix(TABLE_PREFIX);

        generator.setStrategy(strategy);
        generator.setTemplateEngine(new VelocityTemplateEngine());
        generator.execute();
    }
}